package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: hea7en
 * @Date: 2024/5/26 5:13 PM
 * @Description: 报表统计业务实现类
 */
@Slf4j
@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    WorkspaceService workspaceService;

    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        // 日期集合，存放从开始日期到结束日期的所有日期
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        // 循环向后增加1天，直到结束日期
        while (ObjectUtils.notEqual(begin, end)) {
            begin = begin.plusDays(1);
            dateList.add(begin);
        }

        // 遍历日期，获取到每日营业额总计
        List<Double> turnoverDateList =  new ArrayList<>();
        dateList.forEach(date -> {
            Map<String, Object> paramMap = new HashMap<>(12);
            paramMap.put("begin", LocalDateTime.of(date, LocalTime.MIN));
            paramMap.put("end", LocalDateTime.of(date, LocalTime.MAX));
            paramMap.put("status", Orders.COMPLETED);
            Double amount = orderMapper.sumByMap(paramMap);
            turnoverDateList.add(amount == null ? 0.0 : amount);
        });

        // 将集合转成字符串，以逗号分隔
//    String dateStr = dateList.stream().map(date -> date.toString()).collect(Collectors.joining(","));
        String dateStr = StringUtils.join(dateList, ",");
        String turnoverStr = StringUtils.join(turnoverDateList, ",");

        return TurnoverReportVO
                .builder()
                .dateList(dateStr)
                .turnoverList(turnoverStr)
                .build();
    }

    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        // 日期集合，存放从开始日期到结束日期的所有日期
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (ObjectUtils.notEqual(begin, end)) {
            begin = begin.plusDays(1);
            dateList.add(begin);
        }

        // 集合用于存放用户总量
        List<Integer> totalUserList = new ArrayList<>();
        // 集合用于存放新增用户量
        List<Integer> newUserList = new ArrayList<>();

        dateList.forEach(date -> {
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);

            Map<String, Object> params = new HashMap<>(12);
            // 查询用户总量
            params.put("end", endTime);
            Integer totalNum = userMapper.countByMap(params);
            totalUserList.add(totalNum==null?0:totalNum);

            // 查询新增用户量
            params.put("begin", beginTime);
            Integer newNum = userMapper.countByMap(params);
            newUserList.add(newNum==null?0:newNum);
        });

        return UserReportVO
                .builder()
                .dateList(StringUtils.join(dateList, ","))
                .totalUserList(StringUtils.join(totalUserList, ","))
                .newUserList(StringUtils.join(newUserList, ","))
                .build();
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        // 日期集合，存放从开始日期到结束日期的所有日期
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (ObjectUtils.notEqual(begin, end)) {
            begin = begin.plusDays(1);
            dateList.add(begin);
        }

       // 每日订单数
        List<Integer> orderCountList = new ArrayList<>();
        // 每日有效订单数
        List<Integer> validOrderCountList = new ArrayList<>();
        dateList.forEach(date -> {
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
            Integer orderCount = getOrderCount(beginTime, endTime, null);
            orderCountList.add(orderCount == null ? 0 : orderCount);

            Integer validOrderCount = getOrderCount(beginTime, endTime, Orders.COMPLETED);
            validOrderCountList.add(validOrderCount == null ? 0 : validOrderCount);
        });

        // 订单总数
        // reduce累积操作两种不同的写法：1.reduce(0, (a,b)->a+b) 2.reduce(0, Integer::sum)
        // 手动给了初始值0，就不需要加get()，否则必须加get()获取结果
        Integer orderSum = orderCountList.stream().reduce(Integer::sum).get();

        // 有效订单数
        Integer validOrderSum = validOrderCountList.stream().reduce(0, (a,b)->a+b);

        // 订单完成率，除数不能为0
        Double orderCompletionRate = orderSum!=0 ? validOrderSum.doubleValue() / orderSum : 0.0;

        return OrderReportVO.builder()
                .dateList(StringUtils.join(dateList, ","))
                .orderCountList(StringUtils.join(orderCountList, ","))
                .validOrderCountList(StringUtils.join(validOrderCountList, ","))
                .totalOrderCount(orderSum)
                .validOrderCount(validOrderSum)
                .orderCompletionRate(orderCompletionRate)
                .build();

    }

    @Override
    public SalesTop10ReportVO salesTopTen(LocalDate begin, LocalDate end) {
        // 查询到销量排名前十的数据
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        List<GoodsSalesDTO> salesTopTen = orderMapper.getSalesTopTen(beginTime, endTime);

        // 获取到名称并转换为字符串，用逗号分割
        String nameList = salesTopTen.stream()
                .map(GoodsSalesDTO::getName)
                .collect(Collectors.joining(","));

        // 获取到销量并转换为字符串，用逗号分割
        String numberList = salesTopTen.stream()
                .map(GoodsSalesDTO::getNumber)
                .map(String::valueOf)
                .collect(Collectors.joining(","));

        // 封装返回对象
        return SalesTop10ReportVO.builder()
                .nameList(nameList)
                .numberList(numberList)
                .build();
    }

    @Override
    public void exportBusinessData(HttpServletResponse response) {
        // 从数据库查询到需要的数据，最近30天数据
        LocalDateTime beginTime = LocalDateTime.now().with(LocalTime.MIN).minusDays(30);
        LocalDateTime endTime = LocalDateTime.now().with(LocalTime.MAX).minusDays(1);
        BusinessDataVO businessData = workspaceService.getBusinessData(beginTime, endTime);

        // 读取本地excel模板
        InputStream resourceStream = this.getClass().getClassLoader().getResourceAsStream("template/report_template.xlsx");
        try (XSSFWorkbook workbook = new XSSFWorkbook(resourceStream)){
            // 给excel模版填入数据
            XSSFSheet sheet = workbook.getSheet("Sheet1");
            // 第一行
            sheet.getRow(1).getCell(1).setCellValue("时间："+beginTime.toLocalDate()+"至"+endTime.toLocalDate());
            // 第二行
            XSSFRow row = sheet.getRow(3);
            row.getCell(2).setCellValue(businessData.getTurnover());
            row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
            row.getCell(6).setCellValue(businessData.getNewUsers());
            // 第三行
            row = sheet.getRow(4);
            row.getCell(2).setCellValue(businessData.getValidOrderCount());
            row.getCell(4).setCellValue(businessData.getUnitPrice());

            // 算出对应每天日期集合
            ArrayList<LocalDateTime> dateTime = new ArrayList<>();
            dateTime.add(beginTime);
            while (ObjectUtils.notEqual(beginTime.toLocalDate(), endTime.toLocalDate())) {
                beginTime = beginTime.plusDays(1);
                dateTime.add(beginTime);
            }
            // 填充明细数据
            int[] num = {0};
            dateTime.forEach(date -> {
                BusinessDataVO data = workspaceService.getBusinessData(date, date.with(LocalTime.MAX));
                XSSFRow rw = sheet.getRow(num[0] + 7);
                rw.getCell(1).setCellValue(date.toLocalDate().toString());
                rw.getCell(2).setCellValue(data.getTurnover());
                rw.getCell(3).setCellValue(data.getValidOrderCount());
                rw.getCell(4).setCellValue(data.getOrderCompletionRate());
                rw.getCell(5).setCellValue(data.getUnitPrice());
                rw.getCell(6).setCellValue(data.getNewUsers());
                num[0]++;
            });

            // 将excel文档下载到浏览器
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if (resourceStream!=null) {
                    resourceStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 获取订单数量
     * @param beginTime
     * @param endTime
     * @param status
     * @return
     */
    private Integer getOrderCount(LocalDateTime beginTime, LocalDateTime endTime, Integer status) {
        Map<String, Object> params = new HashMap<>(12);
        params.put("begin", beginTime);
        params.put("end", endTime);
        params.put("status", status);
        return orderMapper.countByMap(params);
    }
}
